package com.chenssy.register.core;

import com.chenssy.common.core.InstanceInfo;
import com.chenssy.common.core.Lease;
import com.chenssy.common.core.RecentlyChangedServiceInstance;
import com.chenssy.common.dto.DeltaRegistry;
import com.chenssy.common.enums.InstanceChangedOperationEnum;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 注册器
 * @author:chenssy
 * @date:2021/6/30
 */
@Slf4j
public class InstanceRegister {

    private InstanceRegister(){

        RecenlyChangedServiceMonitor serviceMonitor = new RecenlyChangedServiceMonitor();
        serviceMonitor.setDaemon(true);
        serviceMonitor.start();

    }

    public static InstanceRegister getInstance() {
        return StaticSingletonHolder.instance;
    }


    private static class StaticSingletonHolder {
        private static final InstanceRegister instance = new InstanceRegister();
    }

    /**
     * 核心注册表
     * Map<serviceName,Lease<serviceInstance,InstanceInfo>>
     */
    private Map<String,Map<String,Lease<InstanceInfo>>> registry = new HashMap<>();


    /**
     * 最近变更的服务实例队列
     */
    private LinkedList<RecentlyChangedServiceInstance> recentlyChangedQueue = new LinkedList<>();

    /**
     * 注册服务实例
     * @param instanceInfo
     */
    public void register(InstanceInfo instanceInfo) {
        // 将服务实例放入注册表
        Map<String, Lease<InstanceInfo>> leaseMap = registry.get(instanceInfo.getServiceName());
        if (leaseMap == null) {
            leaseMap = new HashMap<>();
            registry.put(instanceInfo.getServiceName(),leaseMap);
        }

        Lease lease = new Lease(instanceInfo);

        leaseMap.put(instanceInfo.getServiceInstanceId(),lease);

        synchronized (InstanceRegister.class) {
            //更新自我保护机制的阈值
            SelfProtector selfProtector = SelfProtector.getInstance();
            selfProtector.setExpectedHeartbeatRate(selfProtector.getExpectedHeartbeatRate() + 2);
            selfProtector.setExpectedHearbeatThreshold((long) (selfProtector.getExpectedHeartbeatRate() * 0.85));
        }

        // 将服务实例放入最近变更注册表
        RecentlyChangedServiceInstance changedServiceInstance = new RecentlyChangedServiceInstance(instanceInfo,System.currentTimeMillis(), InstanceChangedOperationEnum.register.getOperation());
        recentlyChangedQueue.offer(changedServiceInstance);

        log.info("[register] - {}，注册成功，lastRegistTime :{}",instanceInfo.getServiceName(),lease.getRegistrationTimestamp());
    }

    /**
     * 服务续约
     * @param serviceName
     * @param serviceInstanceId
     * @return
     */
    public Boolean renew(String serviceName,String serviceInstanceId) {
        Map<String,Lease<InstanceInfo>> leaseMap = registry.get(serviceName);

        if (leaseMap == null) {
            return false;
        }

        Lease lease = leaseMap.get(serviceInstanceId);
        if (lease == null) {
            return false;
        }

        // 服务续约
        lease.renew();

        // 记录心跳次数
        HearbeatMessureRate hearbeatMessureRate = HearbeatMessureRate.getInstance();
        hearbeatMessureRate.increment();

        log.info("[renew] - 服务[{}]续约成功，lastUpdateTimestamp:{}",serviceName,lease.getLastUpdateTimestamp());

        return true;
    }

    /**
     * 获取注册服务实例
     * @return
     */
    public Map<String,Map<String,Lease<InstanceInfo>>> getAllRegistry() {
        return registry;
    }

    /**
     * 服务下线
     * @param serviceName
     * @param serviceInstanceId
     * @return
     */
    public boolean cancel(String serviceName,String serviceInstanceId) {
        Map<String,Lease<InstanceInfo>> leaseMap = registry.get(serviceName);

        if (leaseMap == null) {
            return false;
        }

        Lease lease = leaseMap.get(serviceInstanceId);
        if (lease == null) {
            return false;
        }

        // 将服务实例放入最近变更注册表
        InstanceInfo instanceInfo = (InstanceInfo) lease.getHolder();
        RecentlyChangedServiceInstance changedServiceInstance = new RecentlyChangedServiceInstance(instanceInfo,System.currentTimeMillis(), InstanceChangedOperationEnum.remove.getOperation());
        recentlyChangedQueue.offer(changedServiceInstance);

        // 删除服务实例
        leaseMap.remove(serviceInstanceId);
        registry.remove(serviceName);

        synchronized (InstanceRegister.class) {
            //更新自我保护机制的阈值
            SelfProtector selfProtector = SelfProtector.getInstance();
            selfProtector.setExpectedHeartbeatRate(selfProtector.getExpectedHeartbeatRate() - 2);
            selfProtector.setExpectedHearbeatThreshold((long) (selfProtector.getExpectedHeartbeatRate() * 0.85));
        }
        return true;
    }

    public synchronized DeltaRegistry getRecentlyChangedRegistry() {
        Long totalCount = 0L;
        for (Map<String,Lease<InstanceInfo>> leaseMap :registry.values()) {
            totalCount += leaseMap.size();
        }

        DeltaRegistry deltaRegistry = new DeltaRegistry(recentlyChangedQueue, totalCount);
        return deltaRegistry;
    }

    /**
     * 最新变更线程监听器
     */
    private class RecenlyChangedServiceMonitor extends Thread {

        @Override
        public void run() {
            while (true) {
                try {
                    synchronized (recentlyChangedQueue) {
                        RecentlyChangedServiceInstance changedServiceInstance = null;
                        long currentTimestamp = System.currentTimeMillis();
                        while ((changedServiceInstance = recentlyChangedQueue.peek()) != null) {
                            if (currentTimestamp - changedServiceInstance.getChangedTimeStamp() > 3 * 60 * 1000) {
                                recentlyChangedQueue.pop();
                            }
                        }
                    }

                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    log.error("[RecenlyChangedServiceMonitor] - error:{}",e);
                }

            }
        }
    }
}
